﻿using Bilibili.Common.Api;
using Bilibili.Common.Database;
using Bilibili.Common.Log;
using Bilibili.Model.Common;
using Bilibili.Model.Resource;
using PCLUntils.Json;
using PCLUntils.Objects;
using RestSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Bilibili.WebClient.Common
{
    public sealed class RestClientEx : IApiClient
    {
        private RestClient Client { get; }
        private readonly Dictionary<string, string> defaultRequestHeaders;
        internal RestClientEx()
        {
            Client = new RestClient();
            defaultRequestHeaders = new Dictionary<string, string>
            {
                { "app-key", "android64" },
                { "x-bili-aurora-zone", "sh001" },
                { "Referrer", Current.HOST },
                { "x-bili-aurora-eid", "UlMFQVcABlAH" },
                { "UserAgent",  Current.API_USER_AGENT }
            };
        }
        public void UpdateClient() { }
        public CookieContainer GetCookies() => default;
        public async Task<UploadImages> UploadImage(FileInfo fileInfo)
        {
            UploadImages model = default;
            try
            {
                ApiInfo apiInfo = new ApiInfo("http://api.vc.bilibili.com/api/v1/image/upload", "&src=bilih5", true);
                using var fileStream = fileInfo.OpenRead();
                var bytes = new byte[fileStream.Length];
                fileStream.Read(bytes, 0, bytes.Length);
                var request = new RestRequest(apiInfo.ToUri(), Method.Post);
                request.AddFile("file_up", bytes, fileInfo.Name);
                var response = await Client.ExecuteAsync(request);
                UploadImages uploadImagesModel = response.Content.ParseObject<UploadImages>();
                if (uploadImagesModel.code == 0)
                {
                    uploadImagesModel.data.image_size = fileInfo.Length / 1024;
                    model = uploadImagesModel.data;
                }
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("UploadImage", ex);
            }
            return model;
        }
        public async Task<string> GetResults(IApiInfo apiInfo)
        {
            string url = apiInfo.ToString();
            return await GetResults(url);
        }
        public async Task<string> GetResults(string url)
        {
            try
            {
                var request = new RestRequest(url, Method.Get);
                var result = await Client.ExecuteAsync(request);
                if (result.IsSuccessful)
                    return result.Content;
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResults", ex);
            }
            return string.Empty;
        }
        public Task<HttpResponseMessage> GetRespone(string url)
        {
            return default;
        }
        public async Task<string> GetResultsWithUrl(string url, ZipType zipType = ZipType.Normal)
        {
            try
            {
                var request = new RestRequest(url, Method.Get);
                request.AddHeader("Cookie", SettingHelper.UserInfoCookie);
                var result = await Client.ExecuteAsync(request);
                if (result.IsSuccessful)
                {
                    switch (zipType)
                    {
                        case ZipType.Normal:
                            {
                                var bytes = result.RawBytes;
                                return Encoding.UTF8.GetString(bytes);
                            }
                        case ZipType.Deflate:
                            {
                                using var stream = new MemoryStream(result.RawBytes);
                                using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress);
                                using StreamReader streamReader = new StreamReader(deflateStream, Encoding.UTF8);
                                return streamReader.ReadToEnd();
                            }
                        case ZipType.GZip:
                            {
                                using var stream = new MemoryStream(result.RawBytes);
                                using GZipStream zipStream = new GZipStream(stream, CompressionMode.Decompress);
                                using StreamReader streamReader = new StreamReader(zipStream, Encoding.UTF8);
                                return streamReader.ReadToEnd();
                            }
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResults", ex);
            }
            return string.Empty;
        }
        public async Task<string> GetResults(string url, string host)
        {
            try
            {
                var request = new RestRequest(url, Method.Get);
                request.AddHeader("Host", host);
                request.AddHeader("Cookie", SettingHelper.UserInfoCookie);
                var result = await Client.ExecuteAsync(request);
                if (result.IsSuccessful)
                    return Encoding.UTF8.GetString(result.RawBytes);
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResults", ex);
            }
            return string.Empty;
        }
        public async Task<(string Data, HttpResponseMessage Message)> GetResultsWithCookies(string url)
        {
            try
            {
                var request = new RestRequest(url, Method.Get);
                var result = await Client.ExecuteAsync(request);
                if (result.IsSuccessful)
                    return (result.Content, null);
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResults", ex);
            }
            return default;
        }
        public async Task<string> PostResults(IApiInfo apiInfo, string postContent)
        {
            var url = apiInfo.ToString();
            return await PostResults(url, postContent);
        }
        public async Task<string> PostResults(string url, string postContent)
        {
            try
            {
                var request = new RestRequest(url, Method.Post);
                var result = await Client.ExecuteAsync(request);
                request.AddJsonBody(postContent, "application/x-www-form-urlencoded");
                if (result.IsSuccessful)
                    return result.Content;
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResults", ex);
            }
            return string.Empty;
        }
        public async Task<(string Data, HttpResponseMessage Message)> PostResultsWithCookies(string url, string postContent)
        {
            try
            {
                var request = new RestRequest(url, Method.Post);
                var result = await Client.ExecuteAsync(request);
                request.AddJsonBody(postContent, "application/x-www-form-urlencoded");
                if (result.IsSuccessful)
                    return (result.Content, null);
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResults", ex);
            }
            return default;
        }
        public async Task<string> PostResultsUtf8(IApiInfo apiInfo, string postContent)
        {
            var url = apiInfo.ToString();
            return await PostResultsUtf8(url, postContent);
        }
        public async Task<string> PostResultsUtf8(string apiInfo, string postContent)
        {
            try
            {
                var request = new RestRequest(apiInfo, Method.Post);
                var result = await Client.ExecuteAsync(request);
                request.AddJsonBody(postContent, "application/x-www-form-urlencoded");
                if (result.IsSuccessful)
                    return Encoding.UTF8.GetString(result.RawBytes);
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResults", ex);
            }
            return string.Empty;
        }
        public async Task<string> PostResults(string url, string postContent, string referer)
        {
            try
            {
                var request = new RestRequest(url, Method.Post);
                request.AddHeader("Referrer", referer);
                request.AddJsonBody(postContent, "application/x-www-form-urlencoded");
                var result = await Client.ExecuteAsync(request);
                if (result.IsSuccessful)
                    return result.Content;
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("PostResults", ex);
            }
            return string.Empty;
        }
        public async Task<string> GetResultsGZip(string url)
        {
            try
            {
                var request = new RestRequest(url, Method.Get);
                var result = await Client.ExecuteAsync(request);
                if (result.IsSuccessful)
                {
                    using MemoryStream stream = new MemoryStream(result.RawBytes);
                    using GZipStream zipStream = new GZipStream(stream, CompressionMode.Decompress);
                    using StreamReader streamReader = new StreamReader(zipStream, Encoding.UTF8);
                    return streamReader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResultsGZip", ex);
            }
            return string.Empty;
        }
        public async Task<string> GetResultsDeflate(string url)
        {
            try
            {
                var request = new RestRequest(url, Method.Get);
                var result = await Client.ExecuteAsync(request);
                if (result.IsSuccessful)
                {
                    using MemoryStream stream = new MemoryStream(result.RawBytes);
                    using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress);
                    using StreamReader streamReader = new StreamReader(deflateStream, Encoding.UTF8);
                    return streamReader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResultsDeflate", ex);
            }
            return string.Empty;
        }
        public async Task<string> GetResultsUTF8Encode(IApiInfo apiInfo)
        {
            string url = apiInfo.ToString();
            return await GetResultsUTF8Encode(url);
        }
        public async Task<string> GetResultsUTF8Encode(string url)
        {
            try
            {
                var request = new RestRequest(url, Method.Get);
                var result = await Client.ExecuteAsync(request);
                var encodeResults = result.RawBytes;
                return Encoding.UTF8.GetString(encodeResults, 0, encodeResults.Length);
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetResultsUTF8Encode", ex);
                return string.Empty;
            }
        }
        public async Task GetImageStream(string url, Action<byte[]> callBack)
        {
            try
            {
                if (url.IsNotEmpty())
                {
                    var request = new RestRequest(url, Method.Get);
                    var result = await Client.ExecuteAsync(request);
                    callBack?.Invoke(result.RawBytes);
                }
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("GetImageStream", ex);
            }
        }
        public void Dispose() { }
    }
}